package cn.tedu.charging.device.warm;

import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.device.mapper.StationMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.dao.DataAccessException;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * 预热类 专门负责 将station数据预热到redis
 */
@Component
@Slf4j
public class StationWarmUp implements ApplicationRunner {
    //station持久层 读取数据库数据
    @Autowired
    private StationMapper stationMapper;
    //redis的模版 写入redis预热
    @Resource
    @Qualifier("redis01")
    private RedisTemplate redisTemplate;
    /**
     * 在当前springboot程序启动 容器创建结束时,run被调用
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.debug("开始缓存预热");
        //1.检查开关
        String warmupSwitch="station_warm_up";
        boolean isExecute=checkWarmupExecute(warmupSwitch);
        if (!isExecute){
            log.debug("缓存预热开关未打开,不执行预热");
            return;
        }else{
            log.debug("缓存预热开关已打开,开始执行预热");
            batchWarmup(1000l);
        }
    }

    private void batchWarmup(long batchSize) {
        //1.先读取total
        Long total = stationMapper.selectCount(null);
        //整除就是商,不整除就是商+1
        long loopSize=total%batchSize==0?total/batchSize:total/batchSize+1;
        for(int i=0;i<loopSize;i++){
            //查询每批的1000条数据 分页读 0~1000 1001~2000
            //pageSize=1000 pageNo=1~loopSize limit 0,1000 limit 1000,1000 limit 2000,1000
            //拼接limit from(i*batchSize),size(batchSize)
            QueryWrapper<ChargingStationPO> queryWrapper=new QueryWrapper<>();
            //不填写查询条件,只填写limit
            queryWrapper.last("limit "+i*batchSize+","+batchSize);
            List<ChargingStationPO> pos = stationMapper.selectList(queryWrapper);
            saveRedisCache(pos);
        }
    }

    private void saveRedisCache(List<ChargingStationPO> pos) {
        List results = redisTemplate.executePipelined(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                //使用pipeline
                for (ChargingStationPO po : pos) {
                    //set charging:station:cache:+stationId po;
                    String stationCacheKey="charging:station:cache:"+po.getId();
                    redisTemplate.opsForValue().set(stationCacheKey,po);
                    //geoadd beijing_stations po.lng po.lat poId;
                    //undo 判断 station所属行政区域 cityCode查询行政区域名称
                    String geoKey="beijing_stations";
                    redisTemplate.opsForGeo().add(geoKey,
                            new Point(po.getStationLng().doubleValue(),po.getStationLat().doubleValue()),
                            po.getId());
                }
                return null;
            }
        });

    }

    private boolean checkWarmupExecute(String warmupSwitch) {
        //incr warmupSwitch
        Long result = redisTemplate.opsForValue().increment(warmupSwitch);
        return result==1;
    }
}
